登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> SoftHub关联区 >> 主题: mysql 5.7 的 ONLY_FULL_GROUP_BY 对代码的影响     [回主站]     [分站链接]
mysql 5.7 的 ONLY_FULL_GROUP_BY 对代码的影响
clq
浏览(254) - 2018-01-15 09:56:05 发表 编辑

关键字: mysql_ver

[2018-01-15 09:59:52 最后更新]

mysql 5.7 的 ONLY_FULL_GROUP_BY 对代码的影响

下面的这篇文章说得很清楚
http://blog.csdn.net/allen_tsang/article/details/54892046
不想深究的话,当 group by 语句换了个 mysql 环境无法正常使用时可考虑去掉这个默认的 ONLY_FULL_GROUP_BY ,
方法有多种,这里是先查询出数据库目前的 sql_mode ,然后删除掉其中的 ONLY_FULL_GROUP_BY , 然后在 my.ini (linux 是 my.cnf) 中
加一行 sql_mode 的参数为这个修改后的值就可以了(已经有的话就替换).例如:

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

这种变量的查看方法为使用 sql 语句 SELECT @@sql_mode;

id     group_id     name     score
1     A     小刚     20
2     B     小明     19
3     B     小花     17
4     C     小红     18

执行sql:
select name, group_id from game group by group_id(记为sql_make_group)

在严格模式下会报错,因为 "B" 对应的 name 字段值有两种,原来 mysql 是直接取第一个了事.
严格来讲这是代码的错误,不过对于已经有历史的代码是不方便改的,所以只好改数据库. 或者按以下文章内容改:

------------------------------------------------
sql_mode=only_full_group_by研读
2017年02月06日 13:45:49

    标签:
    mysql /
    sql /
    laravel

MySQL 5.7.5后only_full_group_by成为sql_mode的默认选项之一,这可能导致一些sql语句失效。

比如下表game:
id     group_id     name     score
1     A     小刚     20
2     B     小明     19
3     B     小花     17
4     C     小红     18

执行sql:
select name, group_id from game group by group_id(记为sql_make_group)
返回:

Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'game.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

    1

解决方法

    把group by字段group_id设成primary key 或者 unique NOT NULL。这个方法在实际操作中没什么意义。

    使用函数any_value把报错的字段name包含起来。如,select any_value(name), group_id from game group by group_id。

    在配置文件my.cnf中关闭sql_mode=ONLY_FULL_GROUP_BY.。msqyl的默认配置是sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION。可以把ONLY_FULL_GROUP_BY去掉,也可以去掉所有选项设置成sql_mode=,如果你确信其他选项不会造成影响的话。

    mysql官方文档有详细解译。

执行成功后,返回结果应该是
name     group_id
小刚     A
小明     B
小红     C
为什么默认设置ONLY_FULL_GROUP_BY限制?

对于上述的报错信息,我的理解是select字段里包含了没有被group by条件唯一确定的字段name。

因为执行sql_make_group语句实际上把两行纪录小明和小花合并成一行,搜索引擎不知道该返回哪一条,所以认为这样的sql是武断的(arbitrary).

解决办法2和3都是禁止检查返回结果的唯一性。
进阶讨论

上述办法可以解决报错的问题,但也说明sql语句本身有逻辑问题。name字段不应该出现在返回结果,因为它是不确定的。

考虑这样的需求:按group_id分组后,找出每组得分最少的人。

执行sql: select any_value(name) as name, group_id, min(score) as score from game group by group_id order by min(score)

返回结果
name     group_id     score
小明     B     17
小红     C     18
小刚     A     20

B组的name是小明(因为小明的id更小),而期望结果应该是小花。

所以单纯使用group by无法实现这样的需求。可以使用临时表的方法:

select id, name,t.group_id, t.score from (select group_id, min(score) as score from game group by group_id order by min(score)) t inner join game on t.group_id=game.group_id and t.score=game.score

如果要实现更为复杂的需求,可以考虑使用group_concat,请参考这里。
Laravel的相关配置

把my.cnf中的ONLY_FULL_GROUP_BY去掉后,laravel的运行结果仍然报错。翻过代码后发现,laravel在每一次请求都会设定sql_mode。实现代码在Illuminate\Database\Connectors\MySqlConnector,不同版本稍有不同。

5.2和5.3可以在config/databse.php修改配置。

[
'connections' =>
    'msyql' => [
        'strict' => true,
        'modes' => [
            'option1',
            'option2',
            ...
        ]
    ],
]   



当strict=true(默认)即采用mysql的默认配置,当然也包含ONLY_FULL_GROUP_BY。
当strict=false即设置sql_mode=NO_ENGINE_SUBSTITUTION。
也可以自定义,在modes下添加相应的配置项。modes的优先级比strict高。





总数:0 页次:1/0 首页 尾页  
总数:0 页次:1/0 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1